package fem2.gui;

import fem2.Model;
import fem2.gui.pm.HofemPipelineFactory;
import inf.swing.IcebSwingUtils;
import inf.timer.Timer;
import inf.timer.swing.TimerActivityPanel;
import inf.vtk.AxesRenderer;
import inf.vtk.VTKCanvas;
import inf.vtk.pm.AdapterManager;
import inf.vtk.pm.IDLabelsPipeline;
import inf.vtk.pm.PipelineCollection;
import inf.vtk.pm.uiswing.IDLabelsPanel;
import inf.vtk.uiswing.VTKViewControlToolbar;
import inf.vtk.uiswing.VTKViewPointToolbar;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;

import vtk.vtkOutputWindow;
import vtk.vtkXMLFileOutputWindow;
import vtk.util.LibraryLoader;

public class Viewer extends JFrame {

	private final class SolveThread extends Thread {

		@Override
		public void run() {
			Timer t = Timer.getInstance();

			solving_ = true;
			setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			try {
				t.start("Solve and postprocess");
				// modelHolder_.solve();
				t.start("Postprocess");
				canvas_.render();
				t.stop();
				t.stop();
			} catch (Throwable e) {
				e.printStackTrace();
				JOptionPane.showMessageDialog(Viewer.this, "Solve failed: " + e, "Error",
						JOptionPane.ERROR_MESSAGE);
			} finally {
				setCursor(null);
				t.stopAll();
				solving_ = false;
			}
		}
	}

	private static final long serialVersionUID = 1L;

	static {
		LibraryLoader.load();
		IcebSwingUtils.setDefaultLookAndFeel();
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
		AdapterManager.getInstance().registerPackage(
				HofemPipelineFactory.class.getPackage().getName());
		vtkOutputWindow ow = new vtkOutputWindow();
		vtkXMLFileOutputWindow w = new vtkXMLFileOutputWindow();
		w.SetFileName("vtk.out");
		ow.SetInstance(w);
	}

	private ModelHolder modelHolder_;
	private VTKCanvas canvas_;
	private JPanel vtkPanel_;
	private final PipelineCollection pipelineCollection_;
	private IDLabelsPanel idLabelsPanel_;
	private JToolBar toolBar_;
	private JPanel southPanel_;
	private SidePanel sidePanel_;
	private boolean solving_;

	// private AnimateToolbar animateToolbar_;

	public Viewer() {
		this(new PipelineCollection(new HofemPipelineFactory()));
	}

	public Viewer(Model m) {
		this();
		setModel(m);
	}

	public Viewer(PipelineCollection pc) {
		pipelineCollection_ = pc;
		setLayout(new BorderLayout(5, 5));
		setJMenuBar(new HofemMenuBar(pipelineCollection_));
		add(getToolbar(), BorderLayout.NORTH);
		add(getSidePanel(), BorderLayout.WEST);
		add(getVtkPanel(), BorderLayout.CENTER);
		add(getSouthPanel(), BorderLayout.SOUTH);
		setSize(1024, 768);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}

	public VTKCanvas getCanvas() {
		if (canvas_ == null) {
			canvas_ = new VTKCanvas();

			canvas_.GetRenderer().SetBackground(0.9, 0.95, 0.9);
			pipelineCollection_.addToCanvas(canvas_);
		}

		return canvas_;
	}

	private IDLabelsPanel getIdLabelsPanel() {
		if (idLabelsPanel_ == null) {
			idLabelsPanel_ = new IDLabelsPanel(
					(IDLabelsPipeline) pipelineCollection_
							.getPart(HofemPipelineFactory.PL_ID_LABELS),
					IDLabelsPanel.Items.ELEMENTS);
		}
		return idLabelsPanel_;
	}

	public ModelHolder getModel() {
		return modelHolder_;
	}

	public ModelHolder getModelHolder() {
		return modelHolder_;
	}

	public int getP() {
		return getSidePanel().getP();
	}

	public PipelineCollection getPipelineCollection() {
		return pipelineCollection_;
	}

	private SidePanel getSidePanel() {
		if (sidePanel_ == null) {
			sidePanel_ = new SidePanel(pipelineCollection_);
		}
		return sidePanel_;
	}

	private JPanel getSouthPanel() {
		if (southPanel_ == null) {
			southPanel_ = new JPanel(new BorderLayout(5, 5));

			// southPanel_.add(getIdLabelsPanel(), BorderLayout.WEST);
			southPanel_.add(new TimerActivityPanel(), BorderLayout.CENTER);
		}
		return southPanel_;
	}

	private JToolBar getToolbar() {
		if (toolBar_ == null) {
			toolBar_ = new JToolBar();
			toolBar_.setFloatable(false);
			toolBar_.add(new VTKViewControlToolbar(getCanvas()));
			toolBar_.add(new VTKViewPointToolbar(getCanvas()));
			// animateToolbar_ = new AnimateToolbar(pipelineCollection_);
			// animateToolbar_.setSize(animateToolbar_.getPreferredSize());
			// toolBar_.add(animateToolbar_);
			toolBar_.add(new Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(
					5000, 0)));
			getContentPane().add(toolBar_, BorderLayout.NORTH);
		}
		return toolBar_;
	}

	private JPanel getVtkPanel() {
		if (vtkPanel_ == null) {
			vtkPanel_ = new JPanel(new GridLayout(1, 1));

			new AxesRenderer(getCanvas());
			vtkPanel_.setBorder(BorderFactory.createLoweredBevelBorder());
			vtkPanel_.add(getCanvas());
		}
		return vtkPanel_;
	}

	public void setModel(Model m) {
		setModel(m, false, false);
	}

	public void setModel(Model m, boolean solve, boolean threaded) {
		// m.getNSSolver().addObserver(new GraphicalNSSolverObserver());
		modelHolder_ = new ModelHolder();
		modelHolder_.setModel(m);
		pipelineCollection_.setModel(modelHolder_);
		getSidePanel().update();
		if (solve) {
			solve(false, threaded);
		}
		canvas_.resetView();
	}

	public void solve(boolean applySettings, boolean threaded) {
		// quick return
		if (solving_) {
			return;
		}

		if (applySettings) {
			getSidePanel().apply();
		}

		if (threaded) {
			new SolveThread().start();
		} else {
			new SolveThread().run();
		}
	}
}
